﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using PostSharp.CodeModel;
using PostSharp.Collections;

namespace MicroContainer.CompileTime.Generators
{
   internal class DelegatesCacheGenerator : ICodeGenerator
   {
      public void Generate(CodeGenerationContext ctx)
      {
         FieldDefDeclaration delegatesCache = new FieldDefDeclaration();
         ctx.ContainerType.Fields.Add(delegatesCache);
         delegatesCache.Attributes = FieldAttributes.Private | FieldAttributes.Static;
         delegatesCache.FieldType =
            ctx.ContainerType.Module.FindType(typeof(ArrayList), BindingOptions.Default);
         delegatesCache.Name = "_delegatesCache";

         MethodDefDeclaration mappingsGetter = new MethodDefDeclaration();
         ctx.ContainerType.Methods.Add(mappingsGetter);
         mappingsGetter.Attributes = MethodAttributes.Family | MethodAttributes.Virtual;
         mappingsGetter.CallingConvention = CallingConvention.HasThis;
         mappingsGetter.Name = "GetMappings";
         mappingsGetter.ReturnParameter = new ParameterDeclaration();
         mappingsGetter.ReturnParameter.Attributes = ParameterAttributes.Retval;
         mappingsGetter.ReturnParameter.ParameterType = ctx.ContainerType.Module.FindType(typeof(ArrayList), BindingOptions.Default);
         mappingsGetter.MethodBody = new MethodBodyDeclaration();
         mappingsGetter.MethodBody.RootInstructionBlock = mappingsGetter.MethodBody.CreateInstructionBlock();

         InstructionBlock block = mappingsGetter.MethodBody.RootInstructionBlock;
         InstructionWriter writer = new InstructionWriter();
         InstructionSequence seq = mappingsGetter.MethodBody.CreateInstructionSequence();
         block.AddInstructionSequence(seq, NodePosition.Before, null);
         writer.AttachInstructionSequence(seq);
         writer.EmitInstructionField(OpCodeNumber.Ldsfld, delegatesCache);
         writer.EmitInstruction(OpCodeNumber.Ret);
         writer.DetachInstructionSequence();
      }
   }
}
